package com.api.syh56.shengyunhui.controller;


import com.api.syh56.shengyunhui.common.CommonResult;
import com.api.syh56.shengyunhui.common.Constants;
import com.api.syh56.shengyunhui.entity.CouponDet;
import com.api.syh56.shengyunhui.entity.PayInfo;
import com.api.syh56.shengyunhui.entity.Quote;
import com.api.syh56.shengyunhui.entity.Waybill;
import com.api.syh56.shengyunhui.exception.BaseException;
import com.api.syh56.shengyunhui.service.*;
import com.api.syh56.shengyunhui.util.CommonUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;

import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.wechat.pay.java.service.refund.model.Status;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;


import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 微信支付回调
 */
@RestController
@RequestMapping("wechatpay")
@Slf4j
public class WechatPayController {

    @Autowired
    private WayBillService wayBillService;

    @Autowired
    private UserService userService;

    @Autowired
    private PayInfoService payInfoService;

    @Autowired
    private QuoteService quoteService;

    @Autowired
    private SystemMessageService systemMessageService;

    @Autowired
    private NotifyService notifyService;

    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private CouponDetService couponDetService;

    /**
     * 支付通知
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Transactional
    @RequestMapping(value = "success", method = RequestMethod.POST)
    public CommonResult<Map<String,String>> wechatpaysuccess(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("支付通知");
        Transaction transaction = notifyService.wechatPayTradeParser(request,response);
        log.info("支付通知的解密数据: {}", transaction);

        //判断是否支付成功
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        if (tradeState.equals(Transaction.TradeStateEnum.SUCCESS)){


            //附加信息
            String attach = transaction.getAttach();
            Map additionalInfo = new Gson().fromJson(attach, Map.class);
            System.out.println(additionalInfo);

            Long waybillId = Long.valueOf(((String) additionalInfo.get("waybillId")));
            String priceType = (String) additionalInfo.get("priceType");
            Long quoteId = Long.valueOf(((String) additionalInfo.get("quoteId")));
            //支付方式  到付 月结 现付
//            Short payMethod = Short.valueOf(((String) additionalInfo.get("payMethod")));

            //运单  报价
            Quote quote = quoteService.getById(quoteId);
            Waybill waybill = wayBillService.getById(waybillId);

            //支付方式  到付 月结 现付
            Short payMethod = waybill.getPayMethod();

            /**
             * 查询支付成功的支付单，将该 payinfo支付单 改为“支付成功”
             */
            //pay_info表 基本查询条件
            QueryWrapper<PayInfo> payInfoQueryWrapper = new QueryWrapper<>();
            payInfoQueryWrapper.lambda()
//                    .eq(PayInfo::getWaybillId,waybillId)
                    .eq(PayInfo::getPayNum,transaction.getOutTradeNo());

            //如果是 到付、月结
            if (Constants.PayMethod.PAY_LATER.equals(payMethod) || Constants.PayMethod.MONTHLY_PAYMENT.equals(payMethod)){


                //修改 运单状态 (待装货)
                if ("deposit".equals(priceType)){
                    //设置订单所有报价的状态
                    System.out.println("修改订单状态");
                    quoteService.confirmQuote(quote);
                    //发送“定金已支付”通知给司机
                    systemMessageService.SendMessageToDriverWhenQuotePaid(quote);

                    //报价信息
                    waybill.setQuoteId(quoteId);
                    waybill.setDriverId(quote.getDriverId());
                    Short payType = waybill.getPayType();
                    if (payType.equals(Constants.WayBillPayType.DEPOSIT)){
                        waybill.setWaybillLock(Constants.WayBillLock.UNLOCK);
                    }
                    log.info(quote.toString());
                    //平台服务费
                    waybill.setOfferInit(quote.getOfferInit());
                    //运费
                    waybill.setOfferEnd(quote.getOfferPrice());
                    //开票总金额（含税）= 运费 + 平台服务费
                    waybill.setOfferAll(waybill.getOfferInit().add(waybill.getOfferEnd()));
                    //实际支付金额
//                    waybill.setActAmount(waybill.getOfferAll());

                    /**
                     * 无需计算
                     */
                    // 税额根据总运费（含税）offerend 四舍五入到两位小数
                    BigDecimal roundedTaxAmount = waybill.getOfferAll().multiply(Constants.taxRate.NINE).setScale(2, BigDecimal.ROUND_HALF_UP);
                    waybill.setTax(CommonUtil.limitAmount(roundedTaxAmount));

                    //开票金额 = 总运费（含税）offerend - 税额
                    waybill.setOfferendMinusTax(waybill.getOfferAll().subtract(waybill.getTax()));



                    //运单定金金额	订单总金额transaction.getAmount().getTotal()，单位为分
                    waybill.setDeposit(new BigDecimal((transaction.getAmount().getTotal())/100));


                    //确认报价时间
                    waybill.setQuoteTime(LocalDateTime.parse(transaction.getSuccessTime(),Constants.DateTimeFormatterType.RFC3339));
                    //车牌号 车牌颜色
                    waybill.setCarNumber(quote.getCarNumber());
                    waybill.setCardColor(quote.getCardColor());
                    //定金支付成功后，更新状态
                    waybill.setWaybillStatus(Constants.WaybillStatus.DEPOSIT_PAID);
                    waybill.setDeliveryStatus(Constants.DeliveryStatus.AWAIT_LOAD);

                    //pay_info表额外查询条件：定金
                    payInfoQueryWrapper.lambda().eq(PayInfo::getAmountType, Constants.AmountType.DEPOSIT);
                }
                //如果是运费，修改状态为已结算
                else {
//                if(waybill.getDeliveryStatus() == Constants.DeliveryStatus.DELIVERED){
                    Long cuoId = waybill.getCuoId();
                    if (cuoId != null && cuoId != 0) {
                        QueryWrapper<CouponDet> wrapper = new QueryWrapper<>();
                        wrapper.lambda().eq(CouponDet::getId,waybill.getCuoId());
                        CouponDet couponDet = couponDetService.getOne(wrapper);
                        couponDet.setCouponStatus(Constants.couponStatus.USED);
                        couponDet.setWid(waybillId);
                        couponDetService.updateById(couponDet);
                    }
                    //结算时间
//                    waybill.setSettleTime(LocalDateTime.now());
                    waybill.setSettleTime(LocalDateTime.parse(transaction.getSuccessTime(),Constants.DateTimeFormatterType.RFC3339));
                    //运费支付成功后，更新状态
                    waybill.setWaybillStatus(Constants.WaybillStatus.SETTLED);
                    waybill.setDeliveryStatus(Constants.DeliveryStatus.SETTLED);

                    //增加 专线 用户余额
                    userService.addBalance(waybill.getDriverId(),waybill.getOfferEnd());

                    //增加 邀请人 积分
                    userService.addInviteIntegral(waybill,waybill.getOfferEnd());

                    //增加 货主和专线 成交量
                    userService.addDelivery(waybill);

//                }else {
//                    log.error("货物未送达");
//                }

                    //pay_info表额外查询条件：运费
                    payInfoQueryWrapper.lambda().eq(PayInfo::getAmountType, Constants.AmountType.SHIPFEE);

                }
                wayBillService.updateById(waybill);

                //根据查询条件查找pay_info并修改支付状态
                PayInfo payInfo = payInfoService.getOne(payInfoQueryWrapper);
                //运单对应的支付订单不存在
                if (Objects.isNull(payInfo)){
                    log.error("运单对应的支付订单不存在");
                }
                payInfo.setState(Constants.PaymentStatus.PAID);
                payInfoService.updateById(payInfo);

                //支付运费才需要进行退款
                if (!"deposit".equals(priceType)){
                    //运单状态更新为：已结算 后货主才可进行退款
                    wechatPayService.wxpayrefund(waybillId, Constants.Role.SHIPER);
                }


                String outTradeNo = transaction.getOutTradeNo();
                if (outTradeNo.substring(0,outTradeNo.length()-3).equals(waybill.getWaybillNumber())){
                    log.info("运单号+字符后 与 交易单号 相同");
                    log.info(transaction.getSuccessTime());
                }
            }
            /**
             * 现付
             */
            else if (Constants.PayMethod.PAY_NOW.equals(payMethod)){
                //设置订单所有报价的状态
                quoteService.confirmQuote(quote);
                //发送“定金已支付”通知给司机
                systemMessageService.SendMessageToDriverWhenQuotePaid(quote);

                log.info("CuoIdWC:"+ quote.getCuoId());
                if (quote.getCuoId() != null && quote.getCuoId() != 0) {
                    QueryWrapper<CouponDet> wrapper = new QueryWrapper<>();
                    wrapper.lambda().eq(CouponDet::getId,quote.getCuoId());
                    CouponDet couponDet = couponDetService.getOne(wrapper);
                    couponDet.setCouponStatus(Constants.couponStatus.USED);
                    couponDet.setWid(quote.getWaybillId());
                    couponDetService.updateById(couponDet);
                }

                //报价信息
                waybill.setQuoteId(quoteId);
                waybill.setDriverId(quote.getDriverId());

                //平台服务费
                waybill.setOfferInit(quote.getOfferInit());
                //运费
                waybill.setOfferEnd(quote.getOfferPrice());
                //开票总金额（含税）= 运费 + 平台服务费
                waybill.setOfferAll(waybill.getOfferInit().add(waybill.getOfferEnd()));

                // 税额根据总运费（含税）offerend 四舍五入到两位小数
                BigDecimal roundedTaxAmount = waybill.getOfferAll().multiply(Constants.taxRate.NINE).setScale(2, BigDecimal.ROUND_HALF_UP);
                waybill.setTax(CommonUtil.limitAmount(roundedTaxAmount));

                //开票金额 = 总运费（含税）offerend - 税额
                waybill.setOfferendMinusTax(waybill.getOfferAll().subtract(waybill.getTax()));

                //现付  定金为0
                waybill.setDeposit(new BigDecimal(0));

                //确认报价时间
                waybill.setQuoteTime(LocalDateTime.parse(transaction.getSuccessTime(),Constants.DateTimeFormatterType.RFC3339));
                //车牌号 车牌颜色
                waybill.setCarNumber(quote.getCarNumber());
                waybill.setCardColor(quote.getCardColor());
                //现付运费支付成功后，更新状态
                waybill.setWaybillStatus(Constants.WaybillStatus.DEPOSIT_PAID);
                waybill.setDeliveryStatus(Constants.DeliveryStatus.AWAIT_LOAD);

                //结算时间 现付情况下 结算时间 = 确认报价时间
                waybill.setSettleTime(LocalDateTime.parse(transaction.getSuccessTime(),Constants.DateTimeFormatterType.RFC3339));

                //增加 专线 用户余额
                userService.addBalance(waybill.getDriverId(),waybill.getOfferEnd());

                //增加 邀请人 积分
                userService.addInviteIntegral(waybill,waybill.getOfferEnd());

                //增加 货主和专线 成交量
                userService.addDelivery(waybill);


                //更新运单信息
                wayBillService.updateById(waybill);

                userService.getCouponNum();
                //pay_info表额外查询条件：运费
                payInfoQueryWrapper.lambda().eq(PayInfo::getAmountType, Constants.AmountType.SHIPFEE);
                //根据查询条件查找pay_info并修改支付状态
                PayInfo payInfo = payInfoService.getOne(payInfoQueryWrapper);
                //运单对应的支付订单不存在
                if (Objects.isNull(payInfo)){
                    log.error("运单对应的支付订单不存在");
                }
                payInfo.setState(Constants.PaymentStatus.PAID);
                payInfoService.updateById(payInfo);
            }


        }
        responseToWeixin(response);
        return null;
    }


    /**
     * 微信支付退款通知
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "refund", method = RequestMethod.POST)
    public CommonResult<String> wechatpayfailed(HttpServletRequest request, HttpServletResponse response) throws Exception {

        RefundNotification refundNotification = notifyService.wechatPayRefundPaser(request,response);

        log.info("支付通知的解密数据: {}", refundNotification);
        Status refundStatus = refundNotification.getRefundStatus();
        if ( refundStatus == Status.SUCCESS){
            String outTradeNo = refundNotification.getOutTradeNo();
            String outRefundNo = refundNotification.getOutRefundNo();
            QueryWrapper<PayInfo> payInfoQueryWrapper = new QueryWrapper<>();
            payInfoQueryWrapper.lambda()
                    .eq(PayInfo::getPayNum,outTradeNo)
                    .eq(PayInfo::getOutRefundNo,outRefundNo);
            PayInfo payInfo = payInfoService.getOne(payInfoQueryWrapper);
            payInfo.setState(Constants.PaymentStatus.REFUNDED);
            payInfoService.updateById(payInfo);
        }else {
            throw new BaseException("退款失败");
        }

        return CommonResult.success("退款成功");
    }


    /**
     * 给微信响应
     * @param response
     */
    private void responseToWeixin(HttpServletResponse response) throws Exception{
        response.setStatus(200);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("code", "SUCCESS");
        map.put("message", "SUCCESS");
        response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
        response.getOutputStream().write(new Gson().toJson(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();
    }



}
